#include "StdAfx.h"
#include "DataPkt.h"

#define DP_STX_REQ    0xA5
#define DP_STX_RSP    0x5A

UINT8 DataPkt::m_MsgId(0);
string DataPkt::m_DevSn("sn1234");
UINT8 DataPkt::m_DevType(1);
UINT8 DataPkt::m_DevId(0);

DataPkt::DataPkt(void)
{
}

DataPkt::~DataPkt(void)
{
}

UINT8 DataPkt::ChkSum(UINT8 *data, UINT32 size)
{
    UINT8 sum = 0;
    
	while (size --)
	{
        sum += *data;
		data ++;
	}

	return sum;
}

void DataPkt::DevInfoSet(const char *DevSn, UINT8 DevId, UINT8 DevType)
{
	m_DevSn = DevSn;
	m_DevId = DevId;
	m_DevType = DevType;
}

void DataPkt::BufReset()
{
	m_Buf.resize(sizeof(DataPktReq) - 1, '0');
	m_Buf += m_DevSn;
}

UINT8* DataPkt::BuyDataUploadReq(BuyData &bd, int &size)
{
	bool add = false;
	int dcnt = 0;

    BufReset();

	AddItem(&bd.WListSn, 4);

	for (int i = 0; i < (int)bd.WList.size(); i ++)
	{
		if (bd.WList[i].Status == WS_DONE)
		{
			dcnt ++;
		}
	}

	for (int i = 0; i < (int)bd.WList.size(); i ++)
	{
		if (bd.WList[i].Status == WS_DONE)
		{
			if (!add)
			{
				m_Buf += "|";
                add = true;
			}
            dcnt --;
            
			AddWList(&bd.WList[i].SortSn, 10);
			
			if (dcnt != 0)
			    m_Buf += "+";
		}   
	}

    return ReqMake(DPCMD_BUY_UPL, &size);
}

void DataPkt::AddWList(const string *src, int n)
{
	for (int i = 0; i < n; i ++)
	{
		m_Buf += src[i];
		if (i < n - 1)
            m_Buf += ",";
	}
}

bool DataPkt::BuyDataUploadRsp(UINT8 *buf, int size)
{
	DataPktRsp *rsp;

	rsp = (DataPktRsp*)buf;

	if (!Check(rsp, size, DPCMD_BUY_UPL))
		return false;

	return true;
}

UINT8* DataPkt::ConfirmReq(int &size)
{
	BufReset();

	return ReqMake(DPCMD_CONFIRM, &size);
}

UINT8* DataPkt::WeightReportReq(WeightReport &wr, int &size)
{
	BufReset();

	ItemAdd(wr.ScaleId.c_str());
	ItemAdd(wr.ScaChkStat.c_str());
	ItemAdd(wr.SortSn.c_str());
	ItemAdd(wr.LevelId.c_str());
	ItemAdd(wr.LevelCode.c_str());
	ItemAdd(wr.Tare.c_str());
	ItemAdd(wr.Weight.c_str());
	ItemAdd(wr.Status.c_str());

	return ReqMake(DPCMD_WEIGHT_REQ, &size);
}

bool DataPkt::WeightReportRsp(UINT8 *buf, int size)
{
	DataPktRsp *rsp;

	rsp = (DataPktRsp*)buf;

	if (!Check(rsp, size, DPCMD_WEIGHT_REQ))
		return false;

	return true;
}

UINT8* DataPkt::SortReportReq(SortReport &sp, int &size)
{
	BufReset();

	ItemAdd(sp.SortSn.c_str());
	ItemAdd(sp.LevelId.c_str());
	ItemAdd(sp.LevelCode.c_str());
	ItemAdd(sp.SortTime.c_str());

	return ReqMake(DPCMD_SORT_REQ, &size);
}

bool DataPkt::SortReportRsp(UINT8 *buf, int size, DpRspSortRep &sr)
{
	DataPktRsp *rsp;
	int dsize;
	string data;

	rsp = (DataPktRsp*)buf;

	if (!Check(rsp, size, DPCMD_SORT_REQ))
		return false;

	data = (char*)rsp->Data;
	dsize = data.length();

	Separate(",", sr.DevSn, 8, data);

	return true;
}

UINT8* DataPkt::OrderFormReq(string cardid, int &size)
{
    BufReset();

    ItemAdd(cardid.c_str());

    return ReqMake(DPCMD_CONT_INQ, &size);
}

bool DataPkt::OrderFormRsp(UINT8 *buf, int size, DpRspContInfo &ci)
{
	DataPktRsp *rsp;
	int dsize;
	string data;

	rsp = (DataPktRsp*)buf;

	if (!Check(rsp, size, DPCMD_CONT_INQ))
		return false;

	data = (char*)rsp->Data;
    dsize = data.length();

	int spos = 0;
	int epos;
	int part = 1;
	string sub;

	for (spos = 0; spos < dsize;)
	{
		switch (part)
		{
		case 1:
			epos = CommaSeparate(ci.Status, 9, data);
            spos = epos + 1;
			break;
		case 2:
			epos = data.find(",", spos);
			sub = data.substr(spos, epos - spos);
            
            ContPlanListFind(ci, sub);
			spos = epos + 1;
			break;
		case 3:
			epos = data.find(",", spos);
			sub = data.substr(spos, epos - spos);

            LevelRatioListFind(ci, sub);
			break;
		default:
			return true;
		}

		part ++;
	}

	return true;
}

void DataPkt::ContPlanListFind(DpRspContInfo &ci, string &src)
{
	ContPlan cp;
	string sub;
	int len;
	int spos = 0;
	int epos = 0;

	len = src.length();

	for (spos = 0; spos < len;)
	{
		epos = src.find("+", spos);
		sub = src.substr(spos, epos - spos);
		spos = epos + 1;

		Separate(";", cp.Type, 3, sub);

		ci.CpList.push_back(cp);

		if (spos == 0)
			return;
	}
}

void DataPkt::LevelRatioListFind(DpRspContInfo &ci, string &src)
{
	LevelRatio lr;
	string sub;
	int len;
	int spos1 = 0;
	int epos1 = 0;
	int epos2 = 0;
	int spos2 = 0;

	len = src.length();

	for (spos1 = 0; spos1 < len;)
	{
		epos1 = src.find("+", spos1);
		sub = src.substr(spos1, epos1 - spos1);
        spos1 = epos1 + 1;

		epos2 = Separate(";", lr.Group, 2, sub);
		sub = sub.substr(epos2 + 1, -1);

        LevelIdListFind(lr, sub);

		ci.LrList.push_back(lr);

		if (spos1 == 0)
			return;
	}
}

void DataPkt::LevelIdListFind(LevelRatio &lr, string &src)
{
	string sub;
	int len;
	int spos = 0;
	int epos = 0;

	len = src.length();

	for (spos = 0; spos < len;)
	{
		epos = src.find(":", spos);
		sub = src.substr(spos, epos - spos);
		spos = epos + 1;
        
		lr.Id.push_back(sub);

		if (spos == 0)
			return;
	}
}

int DataPkt::Separate(const char *str, string &dst, int items, string &src)
{
	int spos = 0, epos;
	string *member;
	int i;

	member = &dst;

	for (i = 0; i < items; i ++)
	{
		epos = src.find(str, spos);

		*member = src.substr(spos, epos - spos);
		spos = epos + 1;

		if (spos == 0)
		{
			break;
		}
		member ++;
	}

	return epos;
}

UINT8* DataPkt::CallNextReq(int &size)
{
    BufReset();

    return ReqMake(DPCMD_CALLNEXT, &size);
}

UINT8* DataPkt::CallRepeatReq(int &size)
{
	BufReset();

	return ReqMake(DPCMD_CALLREPEAT, &size);
}

bool DataPkt::CallRsp(UINT8 *buf, int size, string &num)
{
    DataPktRsp *rsp;
	int dsize;

	rsp = (DataPktRsp*)buf;
	if (buf == NULL || size <= 0)
		return false;

	if (rsp->Stx != DP_STX_RSP)
		return false;

	dsize = OrderReversal(rsp->DSize);

	rsp->Data[dsize] = '\0';
	num = (char*)rsp->Data;

	return true;
}

bool DataPkt::ItemAdd(const char *str)
{
	m_Buf += ",";
	m_Buf += str;

    return true;
}

bool DataPkt::AddItem(const string *src, int n)
{
    for (int i = 0; i < n; i ++)
	{
		m_Buf += ",";
		m_Buf += src[i];
	}

	return true;
}

bool DataPkt::Check(DataPktRsp *rsp, int size, UINT8 cmd)
{
	int dsize;

	if (rsp == NULL || size < sizeof(DataPktRsp) - 1)
		return false;

	if (rsp->Stx != DP_STX_RSP)
		return false;

	if (rsp->Cmd != cmd)
		return false;

	dsize = OrderReversal(rsp->DSize);

	if (size < (int)(dsize + sizeof(DataPktRsp) - 1))
		return false;

	rsp->Data[dsize] = 0;

	return true;
}

int DataPkt::CommaSeparate(string &dst, int items, string &src)
{
	int spos = 0, epos;
    string *member;
    int i;

	member = &dst;

	for (i = 0; i < items; i ++)
	{
		epos = src.find(",", spos);

		*member = src.substr(spos, epos - spos);
		spos = epos + 1;
		
		if (spos == 0)
		{
			break;
		}
		member ++;
	}

	return epos;
}

bool DataPkt::InitPramRsp(UINT8 *buf, UINT size, DpRspInitPrm &parm)
{
	DataPktRsp *rsp;
	string data;
	string sub;
    int len;
	int part = 1;
	int spos = 0;
	int epos = 0;
	int dsize;

	rsp = (DataPktRsp*)buf;
    if (!Check(rsp, size, DPCMD_PARAM_REQ))
		return false;

	data = (char*)rsp->Data;
    len = data.length();
	dsize = OrderReversal(rsp->DSize);
	if (len != dsize)
		return false;

	for (spos = 0; spos < len;)
	{
		epos = data.find(":", spos);
        sub = data.substr(spos, epos - spos);
		spos = epos + 1;

		switch (part)
		{
		case 1:
            CommaSeparate(parm.StartH, 5, sub);
			break;
		case 2:
            CommaSeparate(parm.CallDelay, 1, sub);
			break;
		case 3:
			CommaSeparate(parm.NumLevels, 1, sub);
			break;
		case 4:
			CommaSeparate(parm.StationNum, 1, sub);
			break;
		case 5:
			CommaSeparate(parm.StationName, 1, sub);
			break;
		case 6:
			CommaSeparate(parm.ScaleNum, 1, sub);
			break;
		case 7:
			CommaSeparate(parm.CheckNeed, 1, sub);
			break;
		case 8:
			CommaSeparate(parm.TimeY, 5, sub);
			break;
		case 9:
			CommaSeparate(parm.SysTare, 3, sub);
			break;
		case 10:
			 BuyInfoListFind(parm, sub);
			break;
		case 11:
            CommaSeparate(parm.ZeroTime, 1, sub);
			break;
		case 12:
			CommaSeparate(parm.ZeroDevi, 1, sub);
			break;
		case 13:
			CommaSeparate(parm.ScaleIdChk, 2, sub);
			break;
		case 14:
			CommaSeparate(parm.DecDigits, 1, sub);
			break;
		case 15:
			CommaSeparate(parm.Rounding, 1, sub);
			break;
        default:
			return true;
		}

		if (spos == 0)
			break;

		part ++;
	}

	return true;
}

bool DataPkt::WorkerCheckRsp(UINT8 *buf, int size, DpRspWrkChk &wrchk)
{
    DataPktRsp *rsp;

	rsp = (DataPktRsp*)buf;

	if (!Check(rsp, size, DPCMD_WORKER_CHK))
		return false;

	wrchk.Sorting = rsp->Data[0] - '0';
	wrchk.Weight = rsp->Data[2] - '0';
	wrchk.Check = rsp->Data[4] - '0';

    return true;
}

UINT8* DataPkt::WorkerCheckReq(DpWorkers &w, int &size)
{
	string name;

	BufReset();

    ItemAdd(w.Sorting.Number.data());
    ItemAdd(w.Weight.Number.data());
    ItemAdd(w.Check.Number.data());

	Gb2Utf8(name, w.Sorting.Name);
	ItemAdd(name.data());

    Gb2Utf8(name, w.Weight.Name);
	ItemAdd(name.data());

    Gb2Utf8(name, w.Check.Name);
	ItemAdd(name.data());

	return ReqMake(DPCMD_WORKER_CHK, &size);
}

UINT8* DataPkt::ReqMake(UINT8 cmd, int *size)
{
    DataPktReq *req;
	UINT dsize;
    UINT len;

	req = (DataPktReq*)m_Buf.data();
    len = (UINT)m_Buf.size();
	if (size != NULL)
	{
	    *size = len;	
	}
    
	dsize = len - sizeof(*req) + 1;

	switch (cmd)
	{
	case DPCMD_WORKER_CHK:
	case DPCMD_PARAM_REQ:
	case DPCMD_CALLNEXT:
	case DPCMD_CALLREPEAT:
	case DPCMD_CONT_INQ:
		req->NeedAck = 0;
		req->NeedData = 1;
		break;
	case DPCMD_CONFIRM:
		req->NeedAck = 0;
		req->NeedData = 0;
		break;
	default:
		req->NeedAck = 0;
		req->NeedData = 1;
		break;
	}

	req->Stx = 0xA5;
	req->DevId = m_DevId;
	req->Cmd = cmd;
	req->DevType = m_DevType;
	req->MsgId = m_MsgId ++;
	req->DSize = OrderReversal(dsize);
	req->Stat = ChkSum(req->Data, dsize);

	return (UINT8*)req;
}

void DataPkt::Gb2Utf8(string &dest, string &src)
{
	int len = (int)src.length() + 1;
	wchar_t* woutbuf = new wchar_t[ len ];
	char* outbuf = new char[ len*3 ];
	int n = MultiByteToWideChar( 936, 0, src.c_str(), len, woutbuf, len );
	n = WideCharToMultiByte( CP_UTF8, 0, woutbuf, n, outbuf, len*3, NULL, NULL );
	outbuf[ n ] = 0;

	dest = outbuf;

	delete outbuf;
	delete woutbuf;
}

UINT8* DataPkt::InitParamReq(char *ver, int &size)
{
	BufReset();
    //TODO ItemAdd(ver);

	return ReqMake(DPCMD_PARAM_REQ, &size);
}

UINT32 DataPkt::OrderReversal(UINT32 val)
{
    UINT8 *p;
    UINT32 temp;

	p = (UINT8*)&val;
	temp = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 

	return temp;
}

void DataPkt::BuyInfoListFind(DpRspInitPrm &parm, string &src)
{
	BuyInfo buy;
	string sub;
	int len;
	int spos = 0;
	int epos = 0;

	len = src.length();

	for (spos = 0; spos < len;)
	{
		epos = src.find("+", spos);
		sub = src.substr(spos, epos - spos);
		spos = epos + 1;
        
		CommaSeparate(buy.Family, 3, sub);
		parm.BuyInfoList.push_back(buy);
		//TODO 
        
		if (spos == 0)
			return;
	}
}
